#pragma once

#include <jsoncpp/json/json.h>
#include "util.hpp"

#define CRLF "\r\n"
#define CRLF_LEN strlen(CRLF)
#define SPACE " "
#define SPACE_LEN strlen(SPACE)

#define OPS "+-*/%"
#define MY_SELF 1

// 9\r\n100 + 200\r\n
string decode(string &in, uint32_t &len)
{
    assert(len);
    len = 0;
    size_t pos = in.find(CRLF);
    if (pos == string::npos)
    {
        return "";
    }
    string inLen = in.substr(0, pos);
    int Len = atoi(inLen.c_str());
    // 确认剩下长度是否足够
    int suplus = in.size() - pos - 2 * CRLF_LEN;
    if (suplus < Len)
    {
        return "";
    }
    // 获取报文
    string package = in.substr(pos + CRLF_LEN, Len);
    len = Len;
    // 将报文从in中删除
    in.erase(0, pos + Len + 2 * CRLF_LEN);
    return package;
}

string encode(const string &in, uint32_t len)
{
    string encodein = to_string(len);
    encodein += CRLF;
    encodein += in;
    encodein += CRLF;
    return encodein;
}

// 定制请求
class Request
{
public:
    Request()
    {
    }
    ~Request()
    {
    }
    // 序列化
    void serialize(string &out)
    {
        string xstr = to_string(_x);
        string ystr = to_string(_y);
#ifdef MY_SELF
        out += xstr;
        out += SPACE;
        out += _op;
        out += SPACE;
        out += ystr;
#else
#endif
    }
    bool deserialize(const string &in)
    {
#ifdef MY_SELF
        size_t spaceOne = in.find(SPACE);
        size_t spaceTwo = in.rfind(SPACE);
        if (spaceOne == string::npos || spaceTwo == string::npos)
        {
            return false;
        }
        string dataOne = in.substr(0, spaceOne);
        string dataTwo = in.substr(spaceTwo + SPACE_LEN);
        _op = in[spaceOne + SPACE_LEN];
        _x = atoi(dataOne.c_str());
        _y = atoi(dataTwo.c_str());
        return true;
#else
#endif
    }

public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    // 0 100
    void serialize(string &out)
    {
        string exit = to_string(_exitCode);
        string res = to_string(_result);

        out += exit;
        out += SPACE;
        out += res;
    }
    bool deserialize(const string &in)
    {
        size_t pos = in.find(SPACE);
        if (string::npos == pos)
        {
            return false;
        }
        string codestr{in.substr(0, pos)}, resstr(in.substr(pos + SPACE_LEN));
        _exitCode = atoi(codestr.c_str());
        _result = atoi(resstr.c_str());
        return true;
    }

public:
    int _exitCode = 0;
    int _result;
};

bool makeRequst(const string &str, Request &req)
{
    char strtmp[BUFFER_SIZE];
    snprintf(strtmp, sizeof strtmp, "%s", str.c_str());
    char *left = strtok(strtmp, OPS);
    char *right = strtok(nullptr, OPS);
    if (!left || !right)
    {
        return false;
    }
    char mid = str[strlen(left)];
    req._x = atoi(left);
    req._y = atoi(right);
    req._op = mid;
    return true;
}